//"This sample program is provided AS IS and may be used, executed, copied and modified without royalty payment by customer (a) for its own
//instruction and study, (b) in order to develop applications designed to run with an IBM WebSphere product, either for customer's own internal use
//or for redistribution by customer, as part of such an application, in customer's own products. "
//
//(C) COPYRIGHT International Business Machines Corp., 2005,2006
//All Rights Reserved * Licensed Materials - Property of IBM

package com;

import com.ibm.websphere.asynchbeans.Work;

/**
 * This is the wrapper for what we run. We need to make sure that any delegate methods
 * only work in the daemon Thread and thus we may block until the thread gets
 * scheduled to get the real Thread object because the WorkItem doesn't have a method
 * to get the actual Thread being used by the daemon thread.
 * @author Billy Newport and Chris D Johnson
 */
public class RunnableWrapper implements IThread, Work
{
	/**
	 * The runnable to actual invoke when we start.
	 */
	private Runnable command;

	/**
	 * This is the daemon thread. This is only set when the run method
	 * is called. All methods here
	 */
	private Thread t = null;

	/**
	 * Initialize the RunnableWrapper with a real Runnable
	 * @param command the Runnable to wrap.
	 */
	public RunnableWrapper(Runnable command)
	{
		super();
		this.command = command;
	}

	/**
	 * Set the myThread variable and then do a notifyAll to unblock any waiters
	 * on this variable.  Then delegate to the actual Runnable.
	 * @see java.lang.Runnable#run()
	 */
	public void run()
	{
	    synchronized(this)
	    {
			t = Thread.currentThread();
			this.notifyAll();
	    }
		command.run();
	}

	/**
	 * This returns the Thread used for the daemon. Note that it blocks
	 * until the run method is called since the run method is responsible
	 * for setting the thread.
	 * @return the Thread that this Runnable is running on.
	 */
	private synchronized Thread getThread() throws InterruptedException
	{
		try
		{
			if(t == null)
				this.wait();

			return t;
		}
		catch(InterruptedException e)
		{
			// Was interrupted prior to running.
			return null;
		}
	}

	/**
	 * @see com.ibm.websphere.sample.concurrentadapter.IThread#countStackFrames()
     * @deprecated
	 */
	public int countStackFrames()
	{
		try
        {
            return getThread().countStackFrames();
        }
        catch (InterruptedException e)
        {
            IllegalStateException ise = new IllegalStateException("Thread was interrupted prior to running the command.");
            ise.initCause(e);
            throw ise;
        }
	}

	/**
	 * @see com.ibm.websphere.sample.concurrentadapter.IThread#destroy()
     * @deprecated
	 */
	public void destroy()
	{
		try
        {
            getThread().destroy();
        }
        catch (InterruptedException e)
        {
            IllegalStateException ise = new IllegalStateException("Thread was interrupted prior to running the command.");
            ise.initCause(e);
            throw ise;
        }
	}


	/* (non-Javadoc)
	 * @see com.ibm.websphere.sample.concurrentadapter.IThread#getContextClassLoader()
	 */
	public ClassLoader getContextClassLoader()
	{
		try
        {
            return getThread().getContextClassLoader();
        }
        catch (InterruptedException e)
        {
            IllegalStateException ise = new IllegalStateException("Thread was interrupted prior to running the command.");
            ise.initCause(e);
            throw ise;
        }
	}

	/* (non-Javadoc)
	 * @see com.ibm.websphere.sample.concurrentadapter.IThread#interrupt()
	 */
	public void interrupt()
	{
		try
        {
            getThread().interrupt();
        }
        catch (InterruptedException e)
        {
            IllegalStateException ise = new IllegalStateException("Thread was interrupted prior to running the command.");
            ise.initCause(e);
            throw ise;
        }
	}

	/* (non-Javadoc)
	 * @see com.ibm.websphere.sample.concurrentadapter.IThread#isInterrupted()
	 */
	public boolean isInterrupted()
	{
		try
        {
            return getThread().isInterrupted();
        }
        catch (InterruptedException e)
        {
            IllegalStateException ise = new IllegalStateException("Thread was interrupted prior to running the command.");
            ise.initCause(e);
            throw ise;
        }
	}

	/* (non-Javadoc)
	 * @see com.ibm.websphere.sample.concurrentadapter.IThread#setContextClassLoader(java.lang.ClassLoader)
	 */
	public void setContextClassLoader(ClassLoader cl)
	{
		try
        {
            getThread().setContextClassLoader(cl);
        }
        catch (InterruptedException e)
        {
            IllegalStateException ise = new IllegalStateException("Thread was interrupted prior to running the command.");
            ise.initCause(e);
            throw ise;
        }
	}

	/* (non-Javadoc)
	 * @see com.ibm.websphere.sample.concurrentadapter.IThread#start()
	 */
	public void start()
	{
	    // Does nothing.  This Thread is never really started.
	}

	/**
	 * Concurrent doesn't have an explicit 'stop' verb so interrupt for good
	 * measure.
	 * @see com.ibm.websphere.asynchbeans.Work#release()
	 */
	public void release()
	{
		interrupt();
	}
}
